package com.lp.guoguo.service;

import com.lp.guoguo.service.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Service
@Slf4j
public class MultiLevelCacheService {

    @Autowired
    private CacheService localCache;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final long DEFAULT_EXPIRE = 30;

    /**
     * 获取数据，先从本地缓存获取，不存在则从Redis获取
     */
    public Object get(String key, Supplier<Object> dbLoader) {
        // 从本地缓存获取数据
        return localCache.getOrLoad(key, () -> {
            // 从Redis获取数据
            Object value = redisTemplate.opsForValue().get(key);
            // 如果Redis中不存在数据，则从数据库中获取
            if (value == null) {
                value = dbLoader.get();
                // 如果数据库中存在数据，则将数据设置到Redis中，并设置过期时间为30分钟
                if (value != null) {
                    // 设置到Redis，30分钟过期
                    redisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
                }
            }
            return value;
        });
    }

    /**
     * 更新数据
     */
    public void update(String key, Object value) {
        redisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
        localCache.put(key, value);
    }

    /**
     * 删除数据
     */
    public void delete(String key) {
        redisTemplate.delete(key);
        localCache.batchRemove(Collections.singletonList(key));
    }

    /**
     * 批量获取数据
     */
    public Map<String, Object> multiGet(List<String> keys, Supplier<Map<String, Object>> dbLoader) {
        Map<String, Object> result = new HashMap<>();
        List<String> missedKeys = new ArrayList<>();

        // 先从本地缓存获取
        for (String key : keys) {
            Object value = localCache.get(key);
            if (value != null) {
                result.put(key, value);
            } else {
                missedKeys.add(key);
            }
        }

        if (!missedKeys.isEmpty()) {
            // 从Redis批量获取未命中的key
            List<Object> redisValues = redisTemplate.opsForValue().multiGet(missedKeys);
            if (redisValues != null) {
                for (int i = 0; i < missedKeys.size(); i++) {
                    if (redisValues.get(i) != null) {
                        result.put(missedKeys.get(i), redisValues.get(i));
                        // 回填本地缓存
                        localCache.put(missedKeys.get(i), redisValues.get(i));
                    }
                }
            }

            // 仍然未命中的key从数据库加载
            Map<String, Object> dbValues = dbLoader.get();
            if (dbValues != null && !dbValues.isEmpty()) {
                // 批量更新Redis和本地缓存
                dbValues.forEach((key, value) -> {
                    redisTemplate.opsForValue().set(key, value, DEFAULT_EXPIRE, TimeUnit.MINUTES);
                    localCache.put(key, value);
                    result.put(key, value);
                });
            }
        }

        return result;
    }

    /**
     * 批量更新缓存
     */
    public void batchUpdate(Map<String, Object> keyValues) {
        keyValues.forEach((key, value) -> {
            redisTemplate.opsForValue().set(key, value, DEFAULT_EXPIRE, TimeUnit.MINUTES);
            localCache.put(key, value);
        });
    }

    /**
     * 设置缓存，可指定过期时间
     */
    public void set(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
        localCache.put(key, value);
    }

    /**
     * 检查key是否存在
     */
    public boolean exists(String key) {
        // 先检查本地缓存
        if (localCache.get(key) != null) {
            return true;
        }
        // 再检查Redis
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }

    /**
     * 获取缓存剩余过期时间
     */
    public long getExpire(String key) {
        return Optional.ofNullable(redisTemplate.getExpire(key))
                .orElse(-2L);
    }



    /**
     * 简单获取缓存值（无需数据库加载）
     */
    public Object getValue(String key) {
        // 先从本地缓存获取
        Object value = localCache.get(key);
        if (value != null) {
            return value;
        }
        // 从Redis获取
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 简单存储值（带默认过期时间）
     */
    public void setValue(String key, Object value) {
        redisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
        localCache.put(key, value);
    }

    /**
     * 获取指定类型的缓存值
     */
    public <T> T getValue(String key, Class<T> type) {
        Object value = getValue(key);
        if (value == null) {
            return null;
        }
        return type.cast(value);
    }

    /**
     * 获取带默认值的指定类型缓存值
     */
    public <T> T getValue(String key, Class<T> type, T defaultValue) {
        T value = getValue(key, type);
        return value != null ? value : defaultValue;
    }

    /**
     * 获取带数据库加载的指定类型缓存值
     */
    public <T> T get(String key, Class<T> type, Supplier<T> dbLoader) {
        return type.cast(get(key, () -> {
            // 将T类型的Supplier转换为Object类型的Supplier
            return dbLoader.get();
        }));
    }
}
